/**
    MVP Tree data structure using graph database for I/O storage
    Copyright (C) 2014  David G. Starkweather

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    David Starkweather starkd88@gmail.com
**/

package org.phash.mvptree;

import java.util.ArrayList;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;

class MVPInternal extends MVPNode {

    static protected final String VPSTRING = "VantagePoint";

    static protected final String PIVOTS = "PIVOTS";

    static protected final String NTH = "nthchild";

    MVPInternal(Node node){
	super(node);
	int ntype = NodeType.INTERNAL_NODE.ordinal();
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    node.setProperty(NODETYPE, ntype);
	    tx.success();
	} finally {
	    tx.finish();
	}
    }

    void setVantagePoint(Datapoint point, int n){
	Node node = getNode();
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Relationship rel = node.createRelationshipTo(point.getNode(), MVPRelationshipTypes.TO_VP);
	    rel.setProperty(VPSTRING, n);
	    tx.success();
	} finally {
	    tx.finish();
	}
    }

    Datapoint getVantagePoint(int n, NodeFactory nf){
	Node node = getNode();
	Datapoint retDP = null;
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Iterable<Relationship> rels = getNode().getRelationships(MVPRelationshipTypes.TO_VP, Direction.OUTGOING);
	    for (Relationship rel : rels){
		int ordval = (int)rel.getProperty(VPSTRING, -1);
		if (ordval == n){
		    Node vpnode = rel.getEndNode();
		    retDP = nf.createDatapoint(vpnode);
		}
	    }
	    tx.success();
	} finally {
	    tx.finish();
	}
	return retDP;
    }
    
    void setSplitsAt(int n, float[] pivots){
	StringBuilder str = new StringBuilder(PIVOTS);
	str.append(n);
	Node node = getNode();
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    node.setProperty(str.toString(), pivots);
	    tx.success();
	} finally {
	    tx.finish();
	}
    }

    float[] getSplitsAt(int n){
	Node node = getNode();
	StringBuilder str = new StringBuilder(PIVOTS);
	str.append(n);
	float[] splits = null;
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    splits = (float[])getNode().getProperty(str.toString(), null);
	    tx.success();
	} finally {
	    tx.finish();
	}
	
	return splits;
    }

    void setChildNodeAt(MVPNode mvpNode, int n){
	if (mvpNode == null) return;
	Node node = getNode();
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Relationship rel = getNode().createRelationshipTo(mvpNode.getNode(), MVPRelationshipTypes.TO_CHILD);
	    rel.setProperty(NTH, n);
	    tx.success();
	} finally {
	    tx.finish();
	}
    }

    MVPNode getChildNodeAt(int n){
	Node node = getNode();
	MVPNode mvpnode = null;
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Iterable<Relationship> rels = node.getRelationships(MVPRelationshipTypes.TO_CHILD, Direction.OUTGOING);
	    for (Relationship rel : rels){
		int ordval = (int)rel.getProperty(MVPInternal.NTH, -1);
		if (ordval == n){
		    Node endnode = rel.getEndNode();
		    int ntype = (int)endnode.getProperty(NODETYPE, -1);
		    if (ntype == NodeType.INTERNAL_NODE.ordinal()) {
			mvpnode = new MVPInternal(endnode);
		    } else if (ntype == NodeType.LEAF_NODE.ordinal()){		// 
			mvpnode = new MVPLeaf(endnode);
		    }
		    break;
		}
	    }
	    tx.success();
	} finally {
	    tx.finish();
	}
	return  mvpnode;
    }

    void deleteChildNodeAt(int n){
	Node node = getNode();
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Iterable<Relationship> rels = node.getRelationships(MVPRelationshipTypes.TO_CHILD, Direction.OUTGOING);
	    for (Relationship rel: rels){
		int ordval = (int)rel.getProperty(MVPInternal.NTH);
		if (ordval == n){
		    rel.delete();
		    break;
		}
	    }
	    tx.success();
	} finally {
	    tx.finish();
	}
    }
}